/*
Copyright (C) 2021-2025 Casa Xu (also Zhiyan Xu) from HIT

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

/*
 * LOS_TMTC.c
 *
 *  Created on: 2022
 *      Author: 64435
 */

#include "LOS_SYS.h"
#include "LOS_TMTC.h"

LOS_TMTC_t STA_TMTC;

uint8_t tempf = 0;
uint8_t TC_CMD_BUF[400]; //遥控指令缓冲区
uint8_t TC_FCNT = 0;     //遥测帧计数器

uint8_t UP_BUF[TMTC2SD_UPFSIZE+4];     //上注程序缓冲区，前四字节是偏移地址
uint8_t UP_FCNT = 0;     //上注程序读取帧计数器

uint8_t TMPACK_TMTCBasic[130]; 

extern LOS_SemaphoreHandle_t BinSemphr_TC;
extern LOS_SemaphoreHandle_t BinSemphr_UP;

// uint8_t *TCArgBuf;
// FLIGHTTASK_t* NodeNeedArg;  //带有参数的遥控指令，需要先创建链表项再补充参数指针，该变量用来暂存需要存参数的链表项指针
/** @fn void LOS_TMTC_TMSend(uint8_t* tmmsg)
*   @brief 对地遥测发送函数
*   @param[in] tmmsg 遥测包内容
*   @param[in] datalen 数据域的长度，不含7字节包头
*   @note 对UV发送遥测信息，由UV转发至地面。
*/
void LOS_TMTC_TMSend(uint8_t* tmmsg, uint16_t datalen)  
{
    LOS_SNP_t SNP_CMD;    //首部配置结构体
    uint8_t FP_CMD[8];    //首部内容，首部用完以后给其他帧做缓冲区使用
    uint16_t cnt = 0;
    uint8_t frame_cnt = 1; //帧计数
    uint16_t delay = 0;

    if (datalen > 0)
    {
        SNP_CMD.SNP_dest = nID_TTCBoard;    //测控板
        SNP_CMD.SNP_source = 0xF0;          //OBC发送
        SNP_CMD.SNP_rec = 0x00;             //内容识别码：宽带上传模块接收
        SNP_CMD.SNP_len = 8 + 7 + datalen;              //长度（包含首部8字节，包头7字节）
        SNP_CMD.SNP_tran = 0x06;            //0110B,信息传递服务，0x05是图像传输服务
        LOS_CAN_FirstPart(&SNP_CMD,FP_CMD);
        LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, SNP_CMD.SNP_dest, 0X00), FP_CMD, 8);//发送首部
        SNP_CMD.SNP_len -= 8; //发了1帧，长度减8
        while(SNP_CMD.SNP_len > 8)
        {
            for (delay = 0;delay<1000;delay++);
            LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, SNP_CMD.SNP_dest, frame_cnt), &tmmsg[cnt], 8);
            cnt += 8;
            SNP_CMD.SNP_len -= 8;
            frame_cnt += 1;
        }
        LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, SNP_CMD.SNP_dest, 0XFF), &tmmsg[cnt], SNP_CMD.SNP_len);
    }

}

/** @fn void LOS_TMTC_PicSend(uint8_t* pic)
*   @brief 遥测对地发送照片函数
*   @param[in] pic 照片包内容:固定长度为218字节
*   @note 对UV发送小相机照片，由UV转发至地面。规定长度为218字节，由该函数自动完成
*/
void LOS_TMTC_PicSend(uint8_t* pic)
{
    LOS_SNP_t SNP_CMD;    //首部配置结构体
    uint8_t FP_CMD[8];    //首部内容，首部用完以后给其他帧做缓冲区使用
    uint16_t cnt = 0;
    uint8_t frame_cnt = 1; //帧计数
    uint16_t delay = 0;

    SNP_CMD.SNP_dest = nID_TTCBoard;    //测控板
    SNP_CMD.SNP_source = 0xF0;          //OBC发送
    SNP_CMD.SNP_rec = 0x00;             //内容识别码：宽带上传模块接收
    SNP_CMD.SNP_len = 226;              //长度（包含首部,218+8）
    SNP_CMD.SNP_tran = 0x05;            //0x05是图像传输服务
    LOS_CAN_FirstPart(&SNP_CMD,FP_CMD);
    LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, SNP_CMD.SNP_dest, 0X00), FP_CMD, 8);//发送首部
    SNP_CMD.SNP_len -= 8; //发了1帧，长度减8
    while(SNP_CMD.SNP_len > 8)
    {
        for (delay = 0;delay<1000;delay++);
        LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, SNP_CMD.SNP_dest, frame_cnt), &pic[cnt], 8);
        cnt += 8;
        SNP_CMD.SNP_len -= 8;
        frame_cnt += 1;
    }
    LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, SNP_CMD.SNP_dest, 0XFF), &pic[cnt], 2);
}


/** @fn void LOS_CAN_TMTCCallBack(LOS_CANMSG_t* can_re)
*   @brief 遥测遥控CAN中断回调函数
*   @param[in] can_re CAN总线消息结构体
*   @note 按帧处理测控板CAN总线消息
*/
void LOS_CAN_TMTCCallBack(LOS_CANMSG_t* can_re)
{
    //首部校验用法：首部校验通过/未通过会改变canerrflag的值，所有消息会被先存在缓冲区，canerrflag有效时才会转存，无效时舍弃
    uint8_t id_filter[4];
    uint8_t sum = 0;
    uint8_t sum_check = 0;
    static uint8_t canerrflag = 0;         //表示首部校验是否通过，未通过：1，通过：0
    static uint8_t canmsgrec = 0xFF;       //区分数据传输服务消息类型（对应首部的rec，本机工参：0x1  文件数据块：0x2）
    static uint8_t canmsgtype = 0xFF;      //区分数据传输（信息传递）服务、遥控传输服务、文件传输服务
    static uint8_t fourbytesbuf[4];
    static uint8_t up_last = 0;            //上注最后一帧的字节数
    static uint8_t up_framecnt = 0;        //上注帧计数器，用来数有没有漏帧
    static uint16_t lastpacklen = 0;        //最后一包的数据长度
    static uint16_t lencnt = 0;           

    BaseType_t xHigherPriorityTaskWoken;   //RTOS信号量用，别动

    memcpy(id_filter, &(can_re->ID), 4);   //将帧ID分为4个字节存储，便于处理
    if (id_filter[3]==0x00)                //若为首帧
    {
        sum = can_re->msg[0] + can_re->msg[1] + can_re->msg[2] + can_re->msg[3] + can_re->msg[4] + can_re->msg[5] + can_re->msg[6];
        sum_check = 0x100 - sum;
        if (sum_check == can_re->msg[7])   //校验和检查，消息有效性判断
        {
            canerrflag = 0;
        }
        else 
        {
           canerrflag = 1; 
        }

        if (canerrflag)
        {
            LOS_CAN_DoNothing();
        }
        else 
        {
            switch(can_re->msg[2])
            {
                case 0x1F:  //信息传递服务
                canmsgtype = 0;
                break;

                case 0x4F:  //文件传输服务
                canmsgtype = 1;
                break;

                case 0x7F:  //遥控传输服务
                canmsgtype = 3;
                TC_FCNT = 0;
                break;

                default:
                canmsgtype = 0xFF;
                break;
            }

            switch((can_re->msg[6])&0X0F)
            {
                case 1:  //本机工参
                canmsgrec = 1;
                break;

                case 2:  //文件数据块
                canmsgrec = 2;
                if (LOS_UPLOAD_LASTPACK == 1)
                {
                    //获取一下数据长度
                    memcpy(&lastpacklen, &(can_re->msg[0]), 2);
                    lastpacklen = lastpacklen << 3;
                    lastpacklen = lastpacklen >> 5;
                    lastpacklen -= 16;
                    lencnt = lastpacklen;
                }
                break;

                default:
                canmsgrec = 0xFF;
                break;
            }

        }


    }
    else if (id_filter[3]==0xFF)  //若为尾帧
    {
        if (canerrflag)
        {
            LOS_CAN_DoNothing();
        }
        else 
        {
            if (canmsgtype==0)           //信息传递服务
            {
                if (canmsgrec == 1)      //内容为本机工参
                {
                    memcpy(&TMPACK_TMTCBasic[112], &can_re->msg[0], 8);
                }
                else if (canmsgrec == 2) //内容为文件数据块
                {
                    if (LOS_UPLOAD_LASTPACK == 1)
                    {
                        up_last = LOS_UPLOAD_BlockSize % 8;
                        if(up_last == 0)
                        {
                            up_last = 8;
                        }
                        
                        memcpy(&UP_BUF[4 + LOS_UPLOAD_BlockSize - up_last], &(can_re->msg[0]), up_last);
                        lencnt -= up_last;
                        if (lencnt > 0) //有漏的
                        {
                            lencnt = lastpacklen; //重来
                        }
                        else
                        {
                            LOS_BinSemphr_GiveFromISR(BinSemphr_UP, &xHigherPriorityTaskWoken);
                        }
                    }
                    else
                    {
                        up_framecnt++;
                        memcpy(&UP_BUF[236], &(can_re->msg[0]), 8);
                        if (up_framecnt != 30)
                        {
                            //说明该包漏帧，啥也不干，等着计算机重新要这一包
                        }
                        else
                        {
                            LOS_BinSemphr_GiveFromISR(BinSemphr_UP, &xHigherPriorityTaskWoken);
                        }
                    }
                }
            }
            else if (canmsgtype==1)     //文件传输服务
            {

            }
            else if (canmsgtype==3)    //遥控传输服务
            {
                TC_FCNT++;
                memcpy(&TC_CMD_BUF[(TC_FCNT-1)*8], &(can_re->msg[0]), 8);
                LOS_BinSemphr_GiveFromISR(BinSemphr_TC, &xHigherPriorityTaskWoken);
            }
        }
        
        canerrflag = 0;   //最后一帧时清除标志位
        canmsgtype = 0xFF; //同上
    }
    else   //若为中间帧
    {
        if (canerrflag)
        {
            LOS_CAN_DoNothing();
        }
        else 
        {
            if (canmsgtype==0)
            {
                if (canmsgrec == 1)      //内容为本机工参
                {
                    if (id_filter[3]  == 0x01)
                    {

                    }
                    else if (id_filter[3] == 0x07)
                    {
                        fourbytesbuf[0] = can_re->msg[7];
                    }
                    else if (id_filter[3] == 0x08)
                    {
                        fourbytesbuf[1] = can_re->msg[0];
                        fourbytesbuf[2] = can_re->msg[1];
                        fourbytesbuf[3] = can_re->msg[2];
                        memcpy(&STA_TMTC.FTP_FileSize, fourbytesbuf, 4);
                    }

                    memcpy(&TMPACK_TMTCBasic[(id_filter[3] - 1) * 8], &can_re->msg[0], 8);
                }
                else if (canmsgrec == 2) //内容为文件数据块
                {
                    if (id_filter[3]==0x01) //01帧里是偏移地址和数据块长度，保存一下偏移地址，便于写入
                    {
                        memcpy(UP_BUF, &(can_re->msg[0]), 4);
                        up_framecnt = 0; //这一帧没有上注文件数据，记0，下一帧开始记1
                    }
                    else
                    {
                        up_framecnt++;
                        memcpy(&UP_BUF[4 + (id_filter[3]-2)*8], &(can_re->msg[0]), 8);
                        if (LOS_UPLOAD_LASTPACK == 1)
                        {
                            lencnt -= 8;
                        }
                    }
                }
            }
            else if (canmsgtype==1)
            {

            }
            else if (canmsgtype==3)
            {
                TC_FCNT++;
                memcpy(&TC_CMD_BUF[(TC_FCNT-1)*8], &(can_re->msg[0]), 8);
                
            }
        }
    }
}



/* OBC对测控板的遥控指令 */
void LOS_TMTC_CMD(uint8_t* cmd)
{
    LOS_SNP_t SNP_CMD;    //首部配置结构体
    uint8_t FP_CMD[8];    //首部内容
    uint8_t Frame_Count = 1;  //CAN帧计数
    uint8_t Sum_Count = 0;
    uint8_t Sum_FP = 0;
    uint8_t Sum_CMD = 0;
    uint8_t Sum = 0;
    uint8_t cmdtotransmit[20]; //包含校验和的指令内容
    uint8_t*  pcmd;
    uint8_t tran_length = cmd[1];
    pcmd = cmdtotransmit;

    //根据协议，传输长度本身也要占1个字节
    tran_length = tran_length + 1;

    SNP_CMD.SNP_dest = nID_TTCBoard;    //测控板
    SNP_CMD.SNP_source = 0xF0;          //OBC发送
    SNP_CMD.SNP_rec = 0x00;             //内容识别码：宽带上传模块接收
    SNP_CMD.SNP_len = 8+1+tran_length+1;  //长度（包含首部）
    SNP_CMD.SNP_tran = 0x01;            //0001B,信息传递服务
    LOS_CAN_FirstPart(&SNP_CMD,FP_CMD);

    for (Sum_Count=0;Sum_Count<8;Sum_Count++)
    {
        Sum_FP += FP_CMD[Sum_Count];
    }
    LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, nID_TTCBoard, 0X00), FP_CMD, 8);
   
    tran_length += 1;   //+1：指令标识长度为1个字节
    
    for (Sum_Count=0;Sum_Count<tran_length;Sum_Count++)
    {
        cmdtotransmit[Sum_Count] = cmd[Sum_Count];
        Sum_CMD += cmd[Sum_Count];
    }
    Sum = Sum_CMD+ Sum_FP;
    Sum = ~(Sum % 256);
    cmdtotransmit[Sum_Count]=Sum;

    tran_length += 1;   //+1：校验和长度为1个字节

    while(tran_length > 8)
    {
        LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, nID_TTCBoard, Frame_Count++), pcmd, 8);
        tran_length -= 8;
        pcmd += 8;
    }
    LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, nID_TTCBoard, 0XFF), pcmd, tran_length);
}

/** @fn void LOS_TMTC_Reset()
*   @brief 本机复位
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_Reset()
{
    //指令标识 传输长度 传输内容
    uint8_t CMD[2]={0x80,0x00};
    LOS_TMTC_CMD(CMD);
}

/** @fn void LOS_TMTC_GetStatus()
*   @brief 读取测控本机工程参数
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_GetStatus()
{
    //指令标识 传输长度 传输内容
    uint8_t CMD[2]={0x81,0x00};
    LOS_TMTC_CMD(CMD);
}

/** @fn void LOS_TMTC_SetFile(uint8_t filenum)
*   @brief 设置待操作文件
*   @param[in] filenum 待操作文件序号，测控板只有0x00
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_SetFile(uint8_t filenum)
{
    //指令标识 传输长度 传输内容
    uint8_t CMD[3]={0x83,0x01,0x01};
    CMD[2] = filenum;
    LOS_TMTC_CMD(CMD);
}

/** @fn void LOS_TMTC_DeleteFile(uint8_t filenum)
*   @brief 删除文件
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_DeleteFile(uint8_t filenum)
{
    //指令标识 传输长度 传输内容
    uint8_t CMD[3]={0x84,0x01,0x01};
    CMD[2] = filenum;
    LOS_TMTC_CMD(CMD);
}

/** @fn void LOS_TMTC_SetTargetnID(uint8_t nID)
*   @brief 设置目标nID
*   @param[in] nID 目标nID
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_SetTargetnID(uint8_t nID)
{
    //指令标识 传输长度 传输内容
    uint8_t CMD[3]={0x85,0x01,0xF0};
    CMD[2] = nID;
    LOS_TMTC_CMD(CMD);
}

/** @fn void LOS_TMTC_ReadBlock(uint32_t offset, uint32_t length)
*   @brief 读取文件数据块
*   @param[in] offset 偏移地址
*   @param[in] length 长度
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_ReadBlock(uint32_t offset, uint32_t length)
{
    //指令标识 传输长度 传输内容
    uint32_t offset_cpy = offset;
    uint32_t length_cpy = length;
    uint8_t CMD[10]={0x86,0x08,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80};
    memcpy(&CMD[2], &offset_cpy, 4);
    memcpy(&CMD[6], &length_cpy, 4);
    LOS_TMTC_CMD(CMD);
}

/** @fn void LOS_TMTC_FTPStart()
*   @brief FTP开始传输
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_FTPStart()
{
    //指令标识 传输长度 传输内容
    uint8_t CMD[2]={0x87,0x00};
    LOS_TMTC_CMD(CMD);
}

/** @fn void LOS_TMTC_FTPStop()
*   @brief FTP停止传输
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_FTPStop()
{
    //指令标识 传输长度 传输内容
    uint8_t CMD[2]={0x88,0x00};
    LOS_TMTC_CMD(CMD);
}

/** @fn void LOS_TMTC_SetSeed(uint8_t* seed)
*   @brief 设置seed
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_SetSeed(uint8_t* seed)
{
    //指令标识 传输长度 传输内容
    uint8_t CMD[18]={0x89,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
    memcpy(&CMD[2], seed, 16);
    LOS_TMTC_CMD(CMD);
}

/** @fn void LOS_TMTC_SetPackCNT(uint16_t cnt)
*   @brief 设置连续传输包数
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_SetPackCNT(uint16_t cnt)
{
    //指令标识 传输长度 传输内容
    uint8_t CMD[4]={0x8A,0x02,0x00,0x00};
    uint16_t cnts = cnt;
    memcpy(&CMD[2], &cnts, 2);
    LOS_TMTC_CMD(CMD);
}

/** @fn void LOS_TMTC_SetFTPInv(uint8_t inv)
*   @brief 设置FTP发送包间隔
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_SetFTPInv(uint8_t inv)
{
    //指令标识 传输长度 传输内容
    uint8_t CMD[3]={0x8B,0x01,0x00};
    CMD[2] = inv;
    LOS_TMTC_CMD(CMD);
}

/** @fn void LOS_TMTC_ArgDownViaRF()
*   @brief 通过无线信道下传本机工程参数
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_ArgDownViaRF()
{
    //指令标识 传输长度 传输内容
    uint8_t CMD[2]={0x91,0x00};
    LOS_TMTC_CMD(CMD);
}

/** @fn void LOS_TMTC_TM30SON()
*   @brief 30s遥测下发开
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_TM30SON()
{
    //指令标识 传输长度 传输内容
    uint8_t CMD[3]={0x92,0x01,0xAA};
    LOS_TMTC_CMD(CMD);
}

/** @fn void LOS_TMTC_TM30SOFF()
*   @brief 30s遥测下发关
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_TM30SOFF()
{
    //指令标识 传输长度 传输内容
    uint8_t CMD[3]={0x92,0x01,0x00};
    LOS_TMTC_CMD(CMD);
}

/** @fn void LOS_TMTC_FileDownViaRF(uint32_t offset, uint32_t length)
*   @brief 通过无线信道下传文件数据块
*   @note 参见宽带上传模块协议
*/
void LOS_TMTC_FileDownViaRF(uint32_t offset, uint32_t length)
{
    //指令标识 传输长度 传输内容
    uint32_t offset_cpy = offset;
    uint32_t length_cpy = length;
    uint8_t CMD[10]={0x94,0x08,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80};
    memcpy(&CMD[2], &offset_cpy, 4);
    memcpy(&CMD[6], &length_cpy, 4);
    LOS_TMTC_CMD(CMD);
}


void LOS_UHF1_PWROn()
{
    LOS_EPS_TCSwitch(19, SWITCH_ON);
}

void LOS_UHF1_PWROff()
{
    LOS_EPS_TCSwitch(19, SWITCH_OFF);
}

void LOS_UHF2_PWROn()
{
    LOS_EPS_TCSwitch(20, SWITCH_ON);
}

void LOS_UHF2_PWROff()
{
    LOS_EPS_TCSwitch(20, SWITCH_OFF);
}

void LOS_VHF1_PWROn()
{
    LOS_EPS_TCSwitch(21, SWITCH_ON);
}

void LOS_VHF1_PWROff()
{
    LOS_EPS_TCSwitch(21, SWITCH_OFF);
}

void LOS_VHF2_PWROn()
{
    LOS_EPS_TCSwitch(22, SWITCH_ON);
}

void LOS_VHF2_PWROff()
{
    LOS_EPS_TCSwitch(22, SWITCH_OFF);
}
